package com.friend.uu;

import android.os.Handler;
import android.os.Message;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Locale;

public class EncryptUtils {
    private static final String EXT_NAME = ".YouJM";
    private static final String CTL_KEY = "asdfg";
    private final int MAX_LENGTH = 4096;//最大加密大小
    private String LOG;
    int endCode;
    private Handler handler;

    public EncryptUtils(Handler handler, int end_code) {
        this.endCode = end_code;
        this.handler = handler;
    }

    //验证密码合法性
    private boolean keyNumIsValid(String key) {
        if (key.length() != 6) {
            LOG += "\n\t警告：密码位数必须是6位";
            return false;
        }
        return true;
    }

    //回传信息
    private void sendMsg(int msgCode) {
        Message msg = new Message();
        msg.what = msgCode;
        msg.obj = LOG;
        handler.sendMessage(msg);
    }

    //加密文件夹内所有可以加密的文件
    public void encryptDir(File dir, String keyString) {
        LOG = "结果：";
        File[] files = dir.listFiles(new FileFilter() {
            @Override
            public boolean accept(File file1) {
                return file1.isFile();
            }
        });
        int n = 0;
        if (files != null && keyNumIsValid(keyString)) {
            for (File file : files) {
                if (encrypt(file, keyString)) n++;
            }
        }
        LOG += String.format(Locale.getDefault(),
                "\n\t总共处理%d个文件 .", n);
        sendMsg(endCode);
    }

    //加密过程
    private boolean encrypt(File sourceFile, String keyString) {
        if (sourceFile.getAbsolutePath().endsWith(EXT_NAME)) return false;

        int n = 1;
        File destFile = new File(sourceFile.getParent(), "YouJM" + n + EXT_NAME);
        while (destFile.exists()) {//检查新文件名
            n++;
            destFile = new File(sourceFile.getParent(), "YouJM" + n + EXT_NAME);
        }

        //加密
        byte[] iBytes, oBytes,
                kBytes = keyString.getBytes();
        try {
            long fLen = sourceFile.length();
            if (fLen < MAX_LENGTH) {
                iBytes = new byte[(int) fLen];
            } else {
                iBytes = new byte[MAX_LENGTH];
            }
            RandomAccessFile ranFile = new RandomAccessFile(sourceFile, "rw");
            ranFile.read(iBytes);
            oBytes = getEncBytes(iBytes, keyString);
            ranFile.seek(0);
            ranFile.write(oBytes);
            //封装文件名，密码
            ranFile.seek(fLen);
            oBytes = sourceFile.getName().getBytes();
            ranFile.write(oBytes);
            ranFile.writeByte(oBytes.length);
            oBytes = getEncBytes(kBytes, CTL_KEY);
            ranFile.write(oBytes);
            ranFile.close();
            //重命名
            //noinspection ResultOfMethodCallIgnored 不检查方法返回值（不加这一条会黄色警告）
            sourceFile.renameTo(destFile);
        } catch (IOException e) {
            LOG += "\n\t错误: " + e.getMessage();
            return false;
        }
        return true;
    }

    //解密文件夹内所有可以解密的文件
    public void decryptDir(File dir, String keyString) {
        LOG = "结果：";
        File[] files = dir.listFiles(new FileFilter() {
            @Override
            public boolean accept(File file1) {
                return file1.isFile();
            }
        });
        int n = 0;
        if (files != null && keyNumIsValid(keyString)) {
            for (File file : files) {
                if (decrypt(file, keyString)) n++;
            }
        }
        LOG += String.format(Locale.getDefault(),
                "\n\t总共处理%d个文件", n);
        sendMsg(endCode);
    }

    //解密过程
    private boolean decrypt(File sourceFile, String keyString) {
        if (!sourceFile.getName().endsWith(EXT_NAME)) return false;
        int keyLen = keyString.getBytes().length;
        byte[] oBytes, iBytes = new byte[keyLen];
        try {
            long fileLen = sourceFile.length();
            RandomAccessFile ranFile = new RandomAccessFile(sourceFile, "rw");
            ranFile.seek(fileLen - keyLen);
            ranFile.read(iBytes);
            if (!new String(getEncBytes(iBytes, CTL_KEY)).equals(keyString)) {
                LOG += "\n\t密码错误: " + sourceFile.getName();
                return false;
            }
            //解密，还原文件名
            ranFile.seek(fileLen - keyLen - 1);
            int num = ranFile.readByte();
            ranFile.seek(fileLen - keyLen - 1 - num);
            iBytes = new byte[num];
            ranFile.read(iBytes);
            File destFile = new File(sourceFile.getParent(), new String(iBytes));
            ranFile.setLength(fileLen - keyLen - num - 1);
            fileLen = ranFile.length();
            if (fileLen < MAX_LENGTH) {
                iBytes = new byte[(int) fileLen];
            } else {
                iBytes = new byte[MAX_LENGTH];
            }
            ranFile.seek(0);
            ranFile.read(iBytes);
            oBytes = getEncBytes(iBytes, keyString);
            ranFile.seek(0);
            ranFile.write(oBytes);
            ranFile.close();
            //noinspection ResultOfMethodCallIgnored
            sourceFile.renameTo(destFile);
        } catch (IOException e) {
            LOG += "\n\t错误：" + e.getMessage();
            return false;
        }
        return true;
    }

    //加密字节数组
    private byte[] getEncBytes(byte[] iBytes, String keyString) {
        byte[] keyBytes = keyString.getBytes();
        byte[] oBytes = new byte[iBytes.length];
        for (int i = 0, j = 0; i < iBytes.length; i++, j++) {
            if (j >= keyBytes.length) j = 0;
            oBytes[i] = (byte) (iBytes[i] ^ keyBytes[j]);
        }
        return oBytes;
    }
}
